/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package languageBasics.javaBeans;


import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/* ########## End of File ########## */

/**
 * Demonstrate the collections issues with beans.
 *
 * @author <a href=mailto:kraythe@arcor.de>Robert Simmons jr. (kraythe)</a>
 * @version $Revision: 1.3 $
 */
public class BeanCollections {
  /** A demo customer set. */
  private static final Set CUSTOMERS;

  static {
    CUSTOMERS = new HashSet();
    try {
      Customer customer = null;
      HashSet purchs = null;

      // -- Joe
      customer = new Customer();
      customer.setName("Joe");
      purchs = new HashSet();
      purchs.add(new Purchase("Cat Food", 22.34f));
      purchs.add(new Purchase("Cat Treats", 5.45f));
      purchs.add(new Purchase("Cat Toy", 12.95f));
      customer.setPurchases(purchs);
      customer.setPurchases2(purchs);
      customer.setPurchases3(purchs);
      CUSTOMERS.add(customer);
      // -- Jon
      customer = new Customer();
      customer.setName("Jon");
      purchs = new HashSet();
      purchs.add(new Purchase("Dog Food", 35.95f));
      purchs.add(new Purchase("Dog Toy", 9.24f));
      customer.setPurchases(purchs);
      customer.setPurchases2(purchs);
      customer.setPurchases3(purchs);
      CUSTOMERS.add(customer);
      // -- Jane
      customer = new Customer();
      customer.setName("Jane");
      purchs = new HashSet();
      customer.setPurchases(purchs);
      customer.setPurchases2(purchs);
      customer.setPurchases3(purchs);
      CUSTOMERS.add(customer);
    } catch (final Exception ex) {
      ex.printStackTrace();
    }
  }

  /**
   * Main Method.
   *
   * @param args
   *          command line arguments.
   */
  public static void main(String[] args) {
    try {
      Iterator iter = CUSTOMERS.iterator();
      Customer customer = null;
      while (iter.hasNext()) {
        customer = (Customer) iter.next();
        someFunction(customer);
        makeCustomerReport(customer);
      }
    } catch (final ClassCastException ex) {
      System.out.println("--- See? I told you. ---");
      ex.printStackTrace(System.out);
      System.out.flush();
    }
    System.out.println();
    System.out.println("--------------------------------------");
    System.out.println();

    // -- Write out the two types of report to show that they
    // do the same thing. Note that the order might be slightly
    // different due to the nature of Set iterators.
    makeGroupReport(CUSTOMERS);

    System.out.println();
    System.out.println("--------------------------------------");
    System.out.println();

    makeGroupReportBetter(CUSTOMERS);
  }

  /**
   * Make a purchases report for a customer.
   *
   * @param customer
   *          The customer for which to make a report.
   *
   * @throws NullPointerException
   *           If customers is null.
   */
  public static void makeCustomerReport(final Customer customer) {
    if (customer == null) {
      throw new NullPointerException();
    }
    Set purchases = customer.getPurchases();
    if (purchases != null) {
      Iterator iter = purchases.iterator();
      Purchase purch = null;
      System.out.println("Purchases for " + customer.getName());
      while (iter.hasNext()) {
        purch = (Purchase) iter.next();
        System.out.println(purch.getItemName() + "\t" + purch.getPrice());
      }
    }
  }

  /**
   * Prepare a report of purchases for the given customers. Example with
   * potential null in Set peoperties.
   *
   * @param customers
   *          The customers for which to prepare a report.
   *
   * @throws NullPointerException
   *           If customers is null.
   */
  public static void makeGroupReport(final Set customers) {
    if (customers == null) {
      throw new NullPointerException();
    }
    Iterator purchaseIter = null;
    Iterator customerIter = null;
    Set purchases = null;
    Customer customer = null;
    Purchase purch = null;

    customerIter = customers.iterator();
    while (customerIter.hasNext()) {
      customer = (Customer) customerIter.next();
      System.out.println("Purchases for " + customer.getName());
      purchases = customer.getPurchases3();
      if (purchases != null) {
        purchaseIter = purchases.iterator();
        while (purchaseIter.hasNext()) {
          purch = (Purchase) purchaseIter.next();
          System.out.println(purch.getItemName() + "\t" + purch.getPrice());
        }
      }
      System.out.print("Total Purchases = ");
      if (purchases != null) {
        System.out.println(purchases.size());
      } else {
        System.out.println(0);
      }
      System.out.println();
    }
  }

  /**
   * Prepare a report of purchases for the given customers. Example with
   * potential no nulls in Set peoperties.
   *
   * @param customers
   *          The customers for which to prepare a report.
   *
   * @throws NullPointerException
   *           If customers is null.
   */
  public static void makeGroupReportBetter(final Set customers) {
    if (customers == null) {
      throw new NullPointerException();
    }
    Iterator purchaseIter = null;
    Iterator customerIter = null;
    Set purchases = null;
    Customer customer = null;
    Purchase purch = null;

    customerIter = customers.iterator();
    while (customerIter.hasNext()) {
      customer = (Customer) customerIter.next();
      System.out.println("Purchases for " + customer.getName());
      purchases = customer.getPurchases3();
      purchaseIter = customer.getPurchases3().iterator();
      while (purchaseIter.hasNext()) {
        purch = (Purchase) purchaseIter.next();
        System.out.println(purch.getItemName() + "\t" + purch.getPrice());
      }
      System.out.println("Total Purchases = " + purchases.size());
      System.out.println();
    }
  }

  /**
   * Manipulate a customer.
   *
   * @param customer
   *          The customer to manipulate.
   *
   * @throws NullPointerException
   *           If customer is null.
   */
  public static void someFunction(final Customer customer) {
    if (customer == null) {
      throw new NullPointerException();
    }
    Set purchs = customer.getPurchases();
    Set names = new HashSet(); // going to use to store customer names.
    names.add(new String("Jason"));
    purchs.add(new String("Fred")); // typo, he meant names, not purchs.
  }
}


/*
 * file: Purchase.java package: oreilly.hcj.collections
 *
 * This software is granted under the terms of the Common Public License, CPL,
 * which may be found at the following URL:
 * http://www-124.ibm.com/developerworks/oss/CPLv1.0.htm
 *
 * Copyright(c) 2003-2005 by the authors indicated in the @author tags. All
 * Rights are Reserved by the various authors.
 *
 * ########## DO NOT EDIT ABOVE THIS LINE ##########
 */

/**
 * A demo purchase bean.
 *
 * @author <a href=mailto:kraythe@arcor.de>Robert Simmons jr. (kraythe)</a>
 * @version $Revision: 1.3 $
 */
class Purchase {
  /** Holder for the property itemName. */
  private String itemName;

  /** Holder for the property price. */
  private float price;

  /**
   * Creates a new Purchase object.
   */
  public Purchase() {
  }

  /**
   * Creates a new Purchase object.
   *
   * @param itemName
   *          The name of the item purchased.
   * @param price
   *          The price of the item purchased.
   */
  public Purchase(final String itemName, final float price) {
    setItemName(itemName);
    setPrice(price);
  }

  /**
   * Setter for the property itemName.
   *
   * @param itemName
   *          The new name.
   */
  public void setItemName(String itemName) {
    this.itemName = itemName;
  }

  /**
   * Getter for the property itemName.
   *
   * @return The current name.
   */
  public String getItemName() {
    return this.itemName;
  }

  /**
   * Setter for the property price.
   *
   * @param price
   *          The new price.
   */
  public void setPrice(float price) {
    this.price = price;
  }

  /**
   * Getter for the property price.
   *
   * @return The current price.
   */
  public float getPrice() {
    return this.price;
  }
}

/* ########## End of File ########## */

/**
 * Demonstration of set functionality in beans.
 *
 * @author <a href=mailto:kraythe@arcor.de>Robert Simmons jr. (kraythe)</a>
 * @version $Revision: 1.3 $
 */
class Customer extends Object implements Serializable {
  /** Use serialVersionUID for interoperability. */
  private static final long serialVersionUID = 7282170508738698519L;

  /** Provides support for property change events. */
  private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

  /** Holds value of property purchases. */
  private Set purchases;

  /** Holds value of property purchases2. */
  private Set purchases2;

  /** Holds value of property purchases3. */
  private Set purchases3 = new HashSet();

  /** Name of the customer. */
  private String name;

  /** Utility field used by constrained properties. */
  private VetoableChangeSupport vetoableChangeSupport = new VetoableChangeSupport(this);

  /**
   * Creates new Customer
   */
  public Customer() {
  }

  /**
   * Setter for the property name.
   *
   * @param name
   *          The new value for the property name.
   *
   * @throws PropertyVetoException
   *           If the change is vetoed.
   */
  public void setName(final String name) throws PropertyVetoException {
    final String oldName = this.name;
    vetoableChangeSupport.fireVetoableChange("name", oldName, this.name);
    this.name = name;
    propertyChangeSupport.firePropertyChange("name", oldName, this.name);
  }

  /**
   * Getter for the property name.
   *
   * @return The current value of the property name.
   */
  public String getName() {
    return this.name;
  }

  /**
   * Setter for property purchases. Note that this doesn't protect the sets as
   * they are given out to the PropertyChangeListener and PropertyVetoListener
   * objects.
   *
   * @param purchases
   *          New value of property purchases.
   *
   * @throws PropertyVetoException
   *           If the change is vetoed.
   */
  public void setPurchases(Set purchases) throws PropertyVetoException {
    Set oldPurchases = this.purchases;
    vetoableChangeSupport.fireVetoableChange("purchases", oldPurchases, this.purchases);
    this.purchases = purchases;
    propertyChangeSupport.firePropertyChange("purchases", oldPurchases, this.purchases);
  }

  /**
   * Getter for property purchases.Note that this doesn't protect the sets as
   * they are given out to the callers of this method.
   *
   * @return Value of property purchases.
   */
  public Set getPurchases() {
    return this.purchases;
  }

  /**
   * Setter for property purchases2.This method fully protects the incomming set
   * so that the vetoable change listener, and the propertyChangeListener cant
   * change it.
   *
   * @param purchases2
   *          New value of property purchases2.
   *
   * @throws PropertyVetoException
   *           If the change is vetoed.
   */
  public void setPurchases2(final Set purchases2) throws PropertyVetoException {
    final Set newPurchases2;
    if (purchases2 != null) {
      newPurchases2 = Collections.unmodifiableSet(purchases2);
    } else {
      newPurchases2 = null;
    }

    final Set oldpurchases2 = this.getPurchases2();
    vetoableChangeSupport.fireVetoableChange("purchases2", oldpurchases2, newPurchases2);
    this.purchases2 = new HashSet(purchases2);
    propertyChangeSupport.firePropertyChange("purchases2", oldpurchases2, getPurchases2());
  }

  /**
   * Getter for property purchases2. Note that you will have to check for null
   * in the return value.
   *
   * @return Value of property purchases2.
   */
  public Set getPurchases2() {
    if (this.purchases2 == null) {
      return null;
    }
    return Collections.unmodifiableSet(this.purchases2);
  }

  /**
   * Setter for property purchases3. This method fully protects the incomming
   * set so that the vetoable change listener, and the propertyChangeListener
   * cant change it. In addition, since the property can never be null, you dont
   * have to worry about checking for null.
   *
   * @param purchases3
   *          New value of property purchases3.
   *
   * @throws PropertyVetoException
   *           If the change is vetoed.
   * @throws NullPointerException
   *           If null is passed for purchases3.
   */
  public void setPurchases3(final Set purchases3) throws PropertyVetoException {
    if (purchases3 == null) {
      throw new NullPointerException();
    }
    final Set oldPurchases3 = this.getPurchases3();
    final Set newPurchases3 = Collections.unmodifiableSet(purchases3);
    vetoableChangeSupport.fireVetoableChange("purchases3", oldPurchases3, newPurchases3);
    this.purchases3 = new HashSet(purchases3);
    propertyChangeSupport.firePropertyChange("purchases3", oldPurchases3, getPurchases3());
  }

  /**
   * Getter for property purchases3.Returns the value of the property. Since the
   * property can never be null, the user has the ability to use the return
   * value without checking for null.
   *
   * @return Value of property purchases3; Note that this will never be null.
   */
  public Set getPurchases3() {
    return Collections.unmodifiableSet(this.purchases3);
  }

  /**
   * @see java.beans.PropertyChangeListener
   */
  public void addPropertyChangeListener(final PropertyChangeListener l) {
    propertyChangeSupport.addPropertyChangeListener(l);
  }

  /**
   * @see java.beans.VetoableChangeListener
   */
  public void addVetoableChangeListener(final VetoableChangeListener l) {
    vetoableChangeSupport.addVetoableChangeListener(l);
  }

  /**
   * @see java.beans.PropertyChangeListener
   */
  public void removePropertyChangeListener(final PropertyChangeListener l) {
    propertyChangeSupport.removePropertyChangeListener(l);
  }

  /**
   * @see java.beans.VetoableChangeListener
   */
  public void removeVetoableChangeListener(final VetoableChangeListener l) {
    vetoableChangeSupport.removeVetoableChangeListener(l);
  }
}

/* ########## End of File ########## */